using MultiAgentsClient.ChatDataStructures;
using MultiAgentsShared;
using static MultiAgentsClient.Manager.MessageManager;
using static MultiAgentsClient.Presentation.ChatInputBoxModel;

namespace MultiAgentsClient.Presentation;

public partial record MentionableModel
{
    private readonly IEventBus eventBus;
    private readonly SynchronizationContext syncContext;

    public int SelectedMentionableIndex = 0;

    public IState<bool> IsMentionableDisplay => State.Value(this, () => false);
    public IListState<AgentDisp> AgentsDisp => ListState<AgentDisp>.Empty(this);
    public IListState<WorkflowDisp> MentionableWorkflowDisp => ListState<WorkflowDisp>.Empty(this);

    public record FillAgentNameCommand(string MentionableAgentName);

    public MentionableModel()
    {
        eventBus = EventBus.Instance;
        syncContext = SynchronizationContext.Current ?? throw Debug.ShouldNotHappen();

        eventBus.Subscribe<MentionableRefreshedCompleteCommand>(async cmd => { await MentionableRefreshedCompleteCommandHandler(cmd); });
        eventBus.Subscribe<InputBoxTabKeyDownCommand>(async cmd => { await InputBoxTabKeyDownCommandHandler(); });
        eventBus.Subscribe<InputBoxUpKeyDownCommand>(async cmd => { await InputBoxUpKeyDownCommandHandler(); });
        eventBus.Subscribe<InputBoxDownKeyDownCommand>(async cmd => { await InputBoxDownKeyDownCommandHandler(); });
    }

    private async Task InputBoxTabKeyDownCommandHandler()
    {
        if (await IsMentionableDisplay == false)
        {
            return;
        }

        IImmutableList<AgentDisp> agentsDisp = await AgentsDisp;
        IImmutableList<WorkflowDisp> mentionableWorkflowDisp = await MentionableWorkflowDisp;

        for (int i = 0; i < agentsDisp.Count; i++)
        {
            if (SelectedMentionableIndex == i)
            {
                await MentionableSelectedCommand(agentsDisp[i].Name);
                return;
            }
        }

        for (int i = agentsDisp.Count; i < (agentsDisp.Count + mentionableWorkflowDisp.Count); i++)
        {
            if (SelectedMentionableIndex == i)
            {
                await MentionableSelectedCommand(mentionableWorkflowDisp[i - agentsDisp.Count].Name);
                return;
            }
        }

        Debug.LogError("Should not happen");
    }

    private async Task InputBoxUpKeyDownCommandHandler()
    {
        IImmutableList<AgentDisp> agentsDisp = await AgentsDisp;
        IImmutableList<WorkflowDisp> mentionableWorkflowDisp = await MentionableWorkflowDisp;

        int totalMentionableCount = agentsDisp.Count + mentionableWorkflowDisp.Count;

        if (totalMentionableCount == 0)
        {
            return;
        }

        if (await IsMentionableDisplay == true)
        {
            SelectedMentionableIndex--;
            if (SelectedMentionableIndex < 0)
            {
                SelectedMentionableIndex = totalMentionableCount - 1;
            }

            await UpdateMentionableHighlight(agentsDisp, mentionableWorkflowDisp, totalMentionableCount);
        }
    }

    private async Task InputBoxDownKeyDownCommandHandler()
    {
        IImmutableList<AgentDisp> agentsDisp = await AgentsDisp;
        IImmutableList<WorkflowDisp> mentionableWorkflowDisp = await MentionableWorkflowDisp;

        int totalMentionableCount = agentsDisp.Count + mentionableWorkflowDisp.Count;

        if (await IsMentionableDisplay == true)
        {
            SelectedMentionableIndex++;
            if (SelectedMentionableIndex > (totalMentionableCount - 1))
            {
                SelectedMentionableIndex = 0;
            }

            await UpdateMentionableHighlight(agentsDisp, mentionableWorkflowDisp, totalMentionableCount);
        }
    }

    public async Task MentionableSelectedCommand(string mentionableName)
    {
        await IsMentionableDisplay.Set(false, default);
        eventBus.Publish(new FillAgentNameCommand(mentionableName));
    }

    private async Task MentionableRefreshedCompleteCommandHandler(MentionableRefreshedCompleteCommand cmd)
    {
        await AgentsDisp.RemoveAllAsync(
            match: item => true,
            ct: default);

        await MentionableWorkflowDisp.RemoveAllAsync(
            match: item => true,
            ct: default);

        if (cmd.AgentsDisp.Count == 0 && cmd.MentionableWorkflowDisp.Count == 0)
        {
            await IsMentionableDisplay.SetAsync(false);
            return;
        }

        await IsMentionableDisplay.SetAsync(true);
        SelectedMentionableIndex = 0;

        foreach (AgentDisp agent in cmd.AgentsDisp)
        {
            await AgentsDisp.AddAsync(agent);
        }

        foreach (WorkflowDisp workflow in cmd.MentionableWorkflowDisp)
        {
            await MentionableWorkflowDisp.AddAsync(workflow);
        }
    }

    private async Task UpdateMentionableHighlight(IImmutableList<AgentDisp> agentsSync, IImmutableList<WorkflowDisp> mentionableWorkflowsSync, int totalMentionableCount)
    {
        var selectedMentionableId = -1;

        //if selected is agent
        if (SelectedMentionableIndex <= (agentsSync.Count - 1))
        {
            selectedMentionableId = agentsSync[SelectedMentionableIndex].Id;
            await AgentsDisp.UpdateAllAsync(
                match: item => true,
                updater: ad => ad.SetHighlight(ad.Id == selectedMentionableId)
                );
            await MentionableWorkflowDisp.UpdateAllAsync(
                match: item => true,
                updater: wf => wf.SetHighlight(false)
                );
        }

        //if selected is workflow
        if (SelectedMentionableIndex > (agentsSync.Count - 1) && SelectedMentionableIndex <= (totalMentionableCount - 1))
        {
            selectedMentionableId = mentionableWorkflowsSync[SelectedMentionableIndex - agentsSync.Count].Id;
            await AgentsDisp.UpdateAllAsync(
                match: item => true,
                updater: ad => ad.SetHighlight(false)
                );
            await MentionableWorkflowDisp.UpdateAllAsync(
                match: item => true,
                updater: wf => wf.SetHighlight(wf.Id == selectedMentionableId)
                );
        }
    }
}
